import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

import 'my_log.dart';

class BLEHelper {
  static const String tag = "BLEHelper";
  static bool debug = true;

  static Future<void> connect(BluetoothDevice device,
      {int attempts = 4}) async {
    debugLog("connect ${device.remoteId.str}");
    int k = 1;

    while (await device.connectionState.first !=
        BluetoothConnectionState.connected) {
      try {
        await device.connect(
            autoConnect: false, timeout: const Duration(seconds: 10));
      } catch (e) {
        MyLog.e(tag, "$e\nconnect: ${device.remoteId.str} attempt: $k");
        await device.disconnect();
        await Future.delayed(const Duration(seconds: 3));
      }
      if (k == attempts) {
        return;
      }
      k++;
    }
    debugLog("${device.remoteId.str} is connected.");
  }

  static Future<List<BluetoothService>> searchService(
      BluetoothDevice device) async {
    var bluetoothDeviceState = await device.connectionState.first;
    debugLog(
        "${device.remoteId.str} 开始搜索GATT Service》》》 ${bluetoothDeviceState.name}");
    if (bluetoothDeviceState != BluetoothConnectionState.connected) {
      await connect(device);
    }
    List<BluetoothService> list = [];
    int k = 1;
    //搜四次
    for (int i = 1; i < 5; i++) {
      //如果蓝牙没有连接，尝试连接
      while (await device.connectionState.first !=
          BluetoothConnectionState.connected) {
        try {
          await device.connect(
              timeout: const Duration(seconds: 10), autoConnect: false);
        } catch (e) {
          MyLog.e(tag,
              "$e\n${await device.connectionState.first}\n ${device.remoteId.str}");
          await device.disconnect();
          await Future.delayed(const Duration(seconds: 1));
        }
        if (k == 4) {
          break;
        }
        k++;
      }
      debugLog("${await device.connectionState.first} ${device.remoteId.str}");
      // await device.clearGattCache();
      if (await device.connectionState.first !=
          BluetoothConnectionState.connected) {
        continue;
      }

      try {
        // 连接后延时3秒
        await Future.delayed(const Duration(seconds: 3));
        // 搜索service
        list = await device.discoverServices().timeout(
              const Duration(seconds: 10),
            );
        debugLog(
            "第$i次搜索 gattService 成功，${device.remoteId.str} 长度${list.length}");
      } catch (e) {
        MyLog.e(tag, "$e\ndiscoverServices 失败-尝试次数：$i ${device.remoteId.str}");
        await device.disconnect();
        // await connect(device);
        MyLog.w(tag, "${device.remoteId.str} disconnected");
      }
      if (list.isNotEmpty) return list;
      await Future.delayed(const Duration(seconds: 1));
    }
    MyLog.e(tag, "${device.remoteId.str} 四次都失败了！！！");

    throw RangeError("BluetoothService list is empty");
  }

  ///发送消息
  static Future<void> writeStringMsg(
      BluetoothCharacteristic bluetoothCharacteristic, String msg) async {
    debugLog("writeMsg: $msg");
    try {
      await bluetoothCharacteristic.write(
        utf8.encode(msg),
      );
      return;
    } catch (e) {
      MyLog.e(tag, e.toString());
    }
  }

  static Future<void> writeListMsg(
      BluetoothCharacteristic bluetoothCharacteristic, List<int> msg) async {
    debugLog("writeMsg: $msg");
    try {
      await bluetoothCharacteristic.write(msg);
      return;
    } catch (e) {
      MyLog.e(tag, e.toString());
    }
  }

  static Future<String> readMsg(
      BluetoothCharacteristic bluetoothCharacteristic) async {
    return String.fromCharCodes(await bluetoothCharacteristic.read()).trim();
  }

  static Future<String> getValue(
      {required BluetoothDevice device, required String msg}) async {
    String value = "";

    // await device.disconnect();
    // await Future.delayed(const Duration(milliseconds: 100));
    var bluetoothDeviceState = await device.connectionState.first;
    if (bluetoothDeviceState != BluetoothConnectionState.connected) {
      await connect(device);
    } else if (bluetoothDeviceState == BluetoothConnectionState.connected) {
      // await disconnected(device);
      await connect(device);
    }
    var bleServices = await searchService(device);
    if (bleServices.isEmpty) throw Exception("BluetoothService list is empty");
    // var bleServices = await compute(searchService, device);
    debugLog("bleServices:${bleServices.length}");
    BluetoothCharacteristic? characteristic;
    if (Platform.isIOS) {
      characteristic = bleServices[0].characteristics[0];
    } else if (Platform.isAndroid) {
      characteristic = bleServices[2].characteristics[0];
    }

    await writeStringMsg(characteristic!, msg);
    await Future.delayed(const Duration(milliseconds: 100));

    do {
      try {
        if (characteristic.properties.read) {
          value = await readMsg(characteristic);
          // WidgetsFlutterBinding.ensureInitialized();
          // value = await compute(readData, characteristic);
        }
      } catch (e) {
        MyLog.e(tag, e.toString());
        await Future.delayed(const Duration(milliseconds: 100));
        try {
          if (characteristic.properties.write) {
            writeStringMsg(characteristic, msg);
          }
        } catch (e) {
          MyLog.e(tag, e.toString());
        }
      }
      await Future.delayed(const Duration(seconds: 1));
    } while (value.isEmpty);

    if (value.isNotEmpty && value != "noip") {
      debugLog("获取到蓝牙数据 value:$value");
    }
    return value.trim();
  }

  ///获取蓝牙特征
  ///[mac]蓝牙MAC地址
  static Future<BluetoothCharacteristic?> getCharacteristic(String mac) async {
    var device = BluetoothDevice.fromId(
      mac,
    );

    var bluetoothDeviceState = await device.connectionState.first;
    if (bluetoothDeviceState != BluetoothConnectionState.connected) {
      // await BLEHelper.disconnected(device);
      //建立连接
      await connect(device);
      try {
        await device.clearGattCache();
      } catch (e) {
        MyLog.e(tag, e.toString());
      }
    }
    BluetoothCharacteristic? characteristic;
    await Future.delayed(const Duration(seconds: 3));
    debugLog("搜索GATT服务 $mac");
    //搜索GATT服务
    var bleServices = await BLEHelper.searchService(device);
    for (var bleService in bleServices) {
      debugLog("bleService: ${bleService.toString()}");
    }
    var bleMac = device.remoteId.str;

    debugLog("获取到GATT服务：${bleServices.length} $bleMac");
    if (Platform.isIOS) {
      characteristic = bleServices[0].characteristics[0];
    } else if (Platform.isAndroid) {
      characteristic = bleServices[2].characteristics[0];
    }
    return characteristic;
  }

  static Future disconnected(BluetoothDevice device) async {
    try {
      var id = await device.disconnect();
      debugLog("disconnected ${device.remoteId.str}");
      return id;
    } catch (e) {
      MyLog.e(tag, e.toString());
      return "";
    }
  }

  static void debugLog(String msg) {
    if (debug) MyLog.i(tag, msg);
  }
}
